using System;

namespace RapidHDL
{
	/// <summary>
	/// Summary description for TopLevelComponent.
	/// </summary>
	public class TopLevelComponent : Component
	{

        public MainClock MainClock;
        public NodeVector MainReset;
        public NodeVector MainStart;

        public NodeVector TestBusRead;
        public NodeVector TestBusWrite;

        //public SDRAMInterface SDRAMInterface;
        public ExternalFIFOInterface FIFOInterface;
        public ExternalFIFOInterface SDRAMInterface;

        public NodeVector IOTest;

		public TopLevelComponent(RapidHardware poRapidHardware)
			: base (poRapidHardware,"TopLevel")	
		{            
            IOTest = this.CreateNodeVector("io_test", 8);

		}

        public void AddMainClock(int piFrequency)
        {
            MainClock = new MainClock(this.RapidHardware);
            MainClock.Frequency = piFrequency;
            //MainClock.ClockIn.Connection = MainClock;
            //this.RapidHardware.SystemInterface.AddSignalSource("MAIN_CLOCK", MainClock.ClockIn, 0);
        }

        public void AddMainReset()
        {
            MainReset = this.CreateNodeVector("main_reset", 1);
            //this.RapidHardware.SystemInterface.AddSignalSource("MAIN_RESET", MainReset, 0);

        }

        public void AddMainStart()
        {
            MainStart = this.CreateNodeVector("main_start", 1);
            //this.RapidHardware.SystemInterface.AddSignalSource("MAIN_START", MainStart, 0);
        }

        public void AddFIFOInterface()
        {
            FIFOInterface = new ExternalFIFOInterface(this, "fifo_ifc", MainClock, MainReset,18,16 );
        }

        public void AddSDRAMInterface()
        {
            SDRAMInterface = new ExternalFIFOInterface(this, "sdram_ifc", MainClock, MainReset, 48, 64);
        }

        public void AddTestBus()
        {
            //if (this.RapidHardware.Settings.UseTestBus)
            //{
                TestBusRead = this.CreateNodeVector("TEST_BUS_READ_I", 13);
                TestBusWrite = this.CreateNodeVector("TEST_BUS_WRITE_O", 13);
            //}
        }

        /*public void WireTestBus()
        {
            TestBusWrite.Join(0);
            Utility.SinkExtraBits(this, TestBusRead);
        }*/

        public void AttachExternalInteface(ExternalInterfaceComponent oExternalInterfaceComponent)
        {
            oParentComponent = oExternalInterfaceComponent;
        }



        public override void GenerateStructure()
        {

            RapidHardware.SystemInterface.AddSignalSource("io_test_source", IOTest, 0);
            RapidHardware.SystemInterface.AddSignalView(".io_test");
            RapidHardware.SystemInterface.HideSignalSource("io_test_source",true);
            RapidHardware.SystemInterface.HideSignalView(".io_test",true);


            if (RapidHardware.Settings.UseTestBus)
            {
                //RapidHardware.SystemInterface.AddSignalSource("test_bus_write", TestBusWrite, 0);
                RapidHardware.SystemInterface.AddSignalView(".TEST_BUS_READ_I");
                RapidHardware.SystemInterface.FormatSignalView(".TEST_BUS_READ_I", SignalFormat.Hex);
            }
        }

        public override bool InitializeSimulation()
        {
            if (MainClock != null)
                ToggleMainClockEvent(0.0);
            return true;
        }

        public void ToggleMainClockEvent(double timeNow)
        {
            RapidHardware.Simulation.Clock.ScheduleClockEvent(1.0 / (double)RapidHardware.Simulation.Clock.Frequency * .5, this.ToggleMainClockEvent);
            if (timeNow > 0)
            {
               MainClock.ToggleClock();
            }
        }

        public void WriteTopVerilog()
        {
            int iSourceCount = RapidHardware.SystemInterface.SignalSources.Count - 1;
            int iViewCount = RapidHardware.SystemInterface.SignalViews.Count - 1;
            
            if (iSourceCount + iViewCount <= 0)
                return;

            if (RapidHardware.Settings.UseFIFO || RapidHardware.Settings.UseSDRAM || RapidHardware.Settings.UseTestBus)
            {
                return;  // not yet supported
            }

            ScriptHelper oScript = new ScriptHelper(RapidHardware);
            oScript.NewFile("TOP.v");
            
            string sVerilog = "module TOP(";
            sVerilog = oScript.BuildString(sVerilog, "CLK_I,", 1);
            if (RapidHardware.Settings.UseReset)
            {
                sVerilog = oScript.BuildString(sVerilog, "RESET_I,", 1);
            }
            foreach (SignalSource oSignal in RapidHardware.SystemInterface.SignalSources.Values)
            {
                if (!oSignal.IsIOTest)
                    sVerilog = oScript.BuildString(sVerilog, oSignal.NameHDL + ",", 1);
            }

            foreach (SignalView oSignal in RapidHardware.SystemInterface.SignalViews.Values)
            {
                if (!oSignal.IsIOTest)
                    sVerilog = oScript.BuildString(sVerilog, oSignal.NameHDL + ",", 1);
            }

            sVerilog = oScript.RemoveStringEnding(sVerilog, 1);
            oScript.WriteLine(sVerilog);
            oScript.WriteLine(");");

            sVerilog = "";
            sVerilog = oScript.BuildString(sVerilog, "input CLK_I;", 1);
            if (RapidHardware.Settings.UseReset)
            {
                sVerilog = oScript.BuildString(sVerilog, "input RESET_I;", 1);
            }
            foreach (SignalSource oSignal in RapidHardware.SystemInterface.SignalSources.Values)
            {
                if (!oSignal.IsIOTest)
                    sVerilog = oScript.BuildString(sVerilog, "input " + oScript.VerilogVector(oSignal.NameHDL, oSignal.Width) + ";", 1);
            }

            foreach (SignalView oSignal in RapidHardware.SystemInterface.SignalViews.Values)
            {
                if (!oSignal.IsIOTest)
                    sVerilog = oScript.BuildString(sVerilog, "output " + oScript.VerilogVector(oSignal.NameHDL, oSignal.Width) + ";", 1);
            }
            oScript.WriteLine(sVerilog);

            oScript.BlankLine();
            oScript.WriteLine("rhdl_TopLevelComponent rhdl ");
            sVerilog = "(";

            Node ndClock = MainClock.ClockIn[0];
            NodeVector oTopLevelCLK = ndClock.Net.SelectCriticalNode(this).ParentNodeVector;
            sVerilog = oScript.BuildString(sVerilog, "." + oTopLevelCLK.Name + "(CLK_I),", 1);
            if (RapidHardware.Settings.UseReset)
            {
                Node ndReset = MainReset[0];
                NodeVector oTopLevelReset = ndReset.Net.SelectCriticalNode(this).ParentNodeVector;
                sVerilog = oScript.BuildString(sVerilog, "." + oTopLevelReset.Name + "(RESET_I),", 1);
            }

            foreach (SignalSource oSignal in RapidHardware.SystemInterface.SignalSources.Values)
            {
                if (!oSignal.IsIOTest)
                {
                NodeVector oTopLevelInput = oSignal.GetTopLevelComponentInput();
                sVerilog = oScript.BuildString(sVerilog, "." + oTopLevelInput.Name + "(" + oSignal.NameHDL + "),", 1);
                }
            }
            foreach (SignalView oSignal in RapidHardware.SystemInterface.SignalViews.Values)
            {
                if (!oSignal.IsIOTest)
                {
                    NodeVector oTopLevelOutput = oSignal.GetTopLevelComponentOutput();
                    sVerilog = oScript.BuildString(sVerilog, "." + oTopLevelOutput.Name + "(" + oSignal.NameHDL + "),", 1);
                }
            }
            sVerilog = oScript.BuildString(sVerilog, ".io_test(8'b00000000)", 1);
            oScript.WriteLine(sVerilog);
            oScript.WriteLine(" );");

            oScript.BlankLine();
            oScript.WriteLine("endmodule");
            oScript.CloseFile();
        }

        public void WriteLeonardoScript()
        {
            string sLibrary = RapidHardware.Settings.SynthLibaray;
            ScriptHelper oScript = new ScriptHelper(RapidHardware);
            oScript.NewFile("leo.txt");
            System.Collections.Generic.List<string> lsDepend = RapidHardware.Structure.TopLevelComponent.ComponentVerilog.GetDependencyList();

            oScript.WriteLine("load_lib /leonardo/" + sLibrary + ".syn");

            string sSourcePath = RapidHardware.Settings.OutputPath.Replace('\\','/');

            foreach (string sDepend in lsDepend)
            {
                oScript.WriteLine("read {" + sSourcePath + sDepend + ".v}");
            }
            oScript.WriteLine("read {" + sSourcePath + "TOP.v}");

            oScript.WriteLine("set_attribute -net CLK_I -name clock_cycle -value 10000");
            oScript.WriteLine("optimize -ta " + sLibrary + " -effort standard -macro -area -hierarchy flatten -pass 4");
            oScript.WriteLine("report_area -cell");
            oScript.WriteLine("apply_rename_rules -ruleset VERILOG");
            oScript.WriteLine("auto_write TOP_SYNTH.v");

            oScript.CloseFile();
        }


	}
}
